interface HumanModel extends Model {
    UpperTorso: BasePart,
    Head: BasePart,
    LowerTorso: BasePart,
}
/**
 * 2D矩形碰撞检测实现
 */

// 轴对齐矩形 (AABB)
export class AABB {
    /** 从角色模型生成一个AABB 
    * @param cframe 参照Cframe
    * @param humanModel 
    * @returns 
    */
    static genAABBByHumanModel(cframe: CFrame, humanModel: HumanModel) {
        /** 底座cframe */
        const cframeOfLowerTorso = humanModel.LowerTorso.CFrame;
        /** 头部cframe */
        const cframeOfHead = humanModel.Head.CFrame;
        /** 厚度设计UpperTorso的深度 */
        const addWidth = humanModel.UpperTorso.Size.Z;
        /** aabb底座中间位置的x坐标 */
        const positionCenterBottomX = (cframeOfLowerTorso.Position.X + (cframeOfHead.Position.X)) / 2;
        /** 相对位置AABBx坐标 */
        const positionCenterBottomObjectSpace
            = cframe.PointToObjectSpace(new Vector3(positionCenterBottomX, cframeOfLowerTorso.Position.Y, 0))
        /** aabb头部与底部的X距离 */
        const posWidth = math.abs(cframeOfLowerTorso.Position.X - cframeOfHead.Position.X)
        /** aabb头部与底部的Y距离 */
        const posHeight = math.abs(cframeOfLowerTorso.Position.Y - cframeOfHead.Position.Y)

        const width = posWidth + addWidth;
        const x = positionCenterBottomObjectSpace.Z * -1 - width / 2
        return new AABB(x, positionCenterBottomObjectSpace.Y, posWidth + addWidth, posHeight + (addWidth / 2));
    }
    /** 从底座中间位置生成一个AABB */
    static genAABBByMiddleBottom(mX: number, mY: number, width: number, height: number) {
        const genAABB = new AABB(mX - width / 2,
            mY,
            width,
            height
        )
        return genAABB;
    }
    /** 返回相对part的相对AABB */
    static AABBtoObjectspace(spacePart: BasePart, t: AABB) {
        /** 相对底座位置 */
        const pos2DtoObject = spacePart.CFrame.PointToObjectSpace(new Vector3(t.x, t.y, 0));
        const genAABB = new AABB(-pos2DtoObject.Z,
            pos2DtoObject.Y,
            t.width,
            t.height
        )
        return genAABB;
    }
    constructor(
        public x: number,
        public y: number,
        public width: number,
        public height: number
    ) { }

    // 获取矩形边界
    getLeft() { return this.x; }
    getRight() { return this.x + this.width; }
    getTop() { return this.y; }
    getBottom() { return this.y + this.height; }

    // 检测与另一个AABB的碰撞
    collidesWith(rect: AABB): boolean {
        return this.getRight() > rect.getLeft() &&
            this.getLeft() < rect.getRight() &&
            this.getBottom() > rect.getTop() &&
            this.getTop() < rect.getBottom();
    }

    // 检测点是否在矩形内
    containsPoint(point: Vector2): boolean {
        return point.x >= this.getLeft() &&
            point.x <= this.getRight() &&
            point.y >= this.getTop() &&
            point.y <= this.getBottom();
    }
}

// 向量类，用于旋转矩形计算
export class Vector2 {
    constructor(public x: number = 0, public y: number = 0) { }

    // 向量加法
    add(v: Vector2): Vector2 {
        return new Vector2(this.x + v.x, this.y + v.y);
    }

    // 向量减法
    subtract(v: Vector2): Vector2 {
        return new Vector2(this.x - v.x, this.y - v.y);
    }

    // 向量点积
    dot(v: Vector2): number {
        return this.x * v.x + this.y * v.y;
    }

    // 向量长度的平方
    lengthSquared(): number {
        return this.x * this.x + this.y * this.y;
    }

    // 向量归一化
    normalize(): Vector2 {
        const len = math.sqrt(this.lengthSquared());
        if (len === 0) return new Vector2();
        return new Vector2(this.x / len, this.y / len);
    }

    // 向量旋转(绕原点)
    rotate(angle: number): Vector2 {
        const cos = math.cos(angle);
        const sin = math.sin(angle);
        return new Vector2(
            this.x * cos - this.y * sin,
            this.x * sin + this.y * cos
        );
    }
}


// 旋转矩形 (OBB)
export class OBB {
    constructor(
        public center: Vector2,
        public halfWidth: number,
        public halfHeight: number,
        public rotation: number = 0 // 旋转角度(弧度)
    ) { }

    // 获取矩形的四个顶点
    getVertices(): Vector2[] {
        const { x, y } = this.center;
        const vertices = [
            new Vector2(x - this.halfWidth, y - this.halfHeight), // 左上
            new Vector2(x + this.halfWidth, y - this.halfHeight), // 右上
            new Vector2(x + this.halfWidth, y + this.halfHeight), // 右下
            new Vector2(x - this.halfWidth, y + this.halfHeight)  // 左下
        ];

        // 如果有旋转，应用旋转
        if (this.rotation !== 0) {
            return vertices.map(v => {
                const rotated = v.subtract(this.center).rotate(this.rotation);
                return rotated.add(this.center);
            });
        }

        return vertices;
    }

    // 获取矩形的边法线(用于SAT检测)
    getNormals(): Vector2[] {
        const vertices = this.getVertices();
        const edges = [
            vertices[1].subtract(vertices[0]), // 上边
            vertices[2].subtract(vertices[1])  // 右边
        ];

        // 计算每条边的法线并归一化
        return edges.map(edge =>
            new Vector2(-edge.y, edge.x).normalize()
        );
    }

    // 计算顶点在轴上的投影范围
    projectOntoAxis(axis: Vector2): { min: number, max: number } {
        const vertices = this.getVertices();
        let max = vertices[0].dot(axis);
        let min = max

        for (let i = 1; i < vertices.size(); i++) {
            const proj = vertices[i].dot(axis);
            if (proj < min) min = proj;
            if (proj > max) max = proj;
        }

        return { min, max };
    }

    // 使用分离轴定理(SAT)检测与另一个OBB的碰撞
    collidesWith(obb: OBB): boolean {
        // 获取两个矩形的所有潜在分离轴
        const axes1 = this.getNormals();
        const axes2 = obb.getNormals();

        // 检查所有轴
        for (const axis of [...axes1, ...axes2]) {
            const proj1 = this.projectOntoAxis(axis);
            const proj2 = obb.projectOntoAxis(axis);

            // 检查投影是否重叠
            if (!this.doProjectionsOverlap(proj1, proj2)) {
                return false; // 找到分离轴，不碰撞
            }
        }

        return true; // 所有轴投影都重叠，碰撞
    }

    // 辅助方法: 检查两个投影区间是否重叠
    private doProjectionsOverlap(
        proj1: { min: number, max: number },
        proj2: { min: number, max: number }
    ): boolean {
        return proj1.max >= proj2.min && proj2.max >= proj1.min;
    }

    // 转换为AABB(忽略旋转，用于粗略检测)
    toAABB(): AABB {
        const vertices = this.getVertices();
        let minX = 0;
        let minY = 0;
        let maxX = 0;
        let maxY = 0;

        for (const v of vertices) {
            if (v.x < minX) minX = v.x;
            if (v.x > maxX) maxX = v.x;
            if (v.y < minY) minY = v.y;
            if (v.y > maxY) maxY = v.y;
        }

        return new AABB(
            minX,
            minY,
            maxX - minX,
            maxY - minY
        );
    }
}

// 碰撞检测工具类
export class CollisionDetector {
    // AABB与AABB碰撞检测
    static AABBCollision(rect1: AABB, rect2: AABB): boolean {
        return rect1.collidesWith(rect2);
    }

    // OBB与OBB碰撞检测
    static OBBCollision(rect1: OBB, rect2: OBB): boolean {
        // 先进行AABB粗略检测，提高性能
        if (!this.AABBCollision(rect1.toAABB(), rect2.toAABB())) {
            return false;
        }

        // 再进行精确的OBB检测
        return rect1.collidesWith(rect2);
    }

    // AABB与OBB碰撞检测
    static AABBvsOBB(aabb: AABB, obb: OBB): boolean {
        // 将AABB转换为OBB进行检测
        const aabbAsOBB = new OBB(
            new Vector2(aabb.x + aabb.width / 2, aabb.y + aabb.height / 2),
            aabb.width / 2,
            aabb.height / 2
        );

        return this.OBBCollision(aabbAsOBB, obb);
    }
}

// 使用示例
function demo() {
    // 创建AABB
    const aabb1 = new AABB(0, 0, 100, 100);
    const aabb2 = new AABB(50, 50, 100, 100);

    // 创建OBB
    const obb1 = new OBB(
        new Vector2(200, 200),
        50, 50,
        math.pi / 4 // 45度旋转
    );

    const obb2 = new OBB(
        new Vector2(250, 250),
        60, 60,
        math.pi / 8 // 22.5度旋转
    );

    // 检测碰撞
    // print("AABB碰撞:", CollisionDetector.AABBCollision(aabb1, aabb2));
    // print("OBB碰撞:", CollisionDetector.OBBCollision(obb1, obb2));
    // print("AABB与OBB碰撞:", CollisionDetector.AABBvsOBB(aabb1, obb1));
}    